/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package marketrmi;

import id2212.homework2.ClientInter;
import java.sql.Statement;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Guillaume, Yann
 */
public class Market extends UnicastRemoteObject implements marketrmi.MarketInter {

    private String marketName = "kistaMarket";
    private static final String DATASOURCE = "marketbdd";
    private Hashtable accountClient;
    private Statement sqlStatement;
    private Statement sqlStatementShowList;

    public static void main(String[] args) {
        try {
            Market bankobj = new Market("kistaMarket");
            System.out.println(bankobj + " is ready.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private synchronized Connection getConnection() throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");
        System.out.println("DRIVER OK ! ");
        Connection connec = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/" + DATASOURCE, "root", "");
        System.out.println("Connection with bdd success !");
        return connec;
    }

    /** Construct a persistently named object. */
    public Market(String name) throws RemoteException, MalformedURLException {
        super();
        this.accountClient = new Hashtable();
        Naming.rebind("rmi://127.0.0.1/kistaMarket", this);
        this.marketName = name;

        // connection to the database
        try {
            Connection connection;
            connection = getConnection();
            sqlStatement = connection.createStatement();
            sqlStatementShowList = connection.createStatement();
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public synchronized AccountClientInter createAccountClient(String name, String passwordMarket, ClientInter client) throws RemoteException, Rejected {
        AccountClient account = (AccountClient) accountClient.get(name);

        if (account != null) {
            System.out.println("Account [" + name + "] exists!!!");
            throw new Rejected("Rejected: Market: "
                    + marketName
                    + " Account for: "
                    + name
                    + " already exists: "
                    + account);
        }
        // Check in the BDD
        ResultSet result = null;
        try {
            result = sqlStatement.executeQuery("SELECT * from client WHERE name='" + name + "'");
            if (result.next()) {
                result.close();
                throw new Rejected("Account already exists in the market bdd");
            } else {
                account = new AccountClient(name, passwordMarket, client, this);
                accountClient.put(name, account);
            }
        } catch (SQLException ex) {
            ex.printStackTrace();
        }

        return (AccountClientInter) account;
    }

    @Override
    public synchronized AccountClientInter getAccount(String name, String passwordMarket, ClientInter client) throws RemoteException, Rejected {
        AccountClientInter acc = (AccountClientInter) accountClient.get(name);
        if (acc != null && passwordMarket.equalsIgnoreCase(acc.getMarketPassword())) {
            System.out.println("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Good passed");
            System.out.println("Market: " + marketName
                    + " Account: " + name
                    + " Get for " + name);

            acc.setClientRef(client);
            return acc;
        } else {
            System.out.println("market account is not in cache, we check the dbb");
            ResultSet result = null;
            try {
                result = sqlStatement.executeQuery("SELECT * from client WHERE name='" + name + "'");
                result.next();
                if ( passwordMarket.equalsIgnoreCase(result.getString("passwordMarket"))) {
                    // account exist, instantiate , put in cache
                    acc = new AccountClient(name, passwordMarket, this);
                    accountClient.put(name, acc);
                    acc.setClientRef(client);
                    result.close();
                    return acc;
                } else {
                    result.close();
                    throw new Rejected("no account with this name/password nor in cache nor in the bdd");
                }
            } catch (SQLException ex) {
                System.out.println("unable to do Market.getAccount " + ex);
            }
        }
        acc.setClientRef(client);
        return acc;
    }

    @Override
    public synchronized AccountClientInter getAccount(String name, String passwordMarket) throws RemoteException, Rejected {
        AccountClientInter acc = (AccountClientInter) accountClient.get(name);
        if (acc != null && passwordMarket.equalsIgnoreCase(acc.getMarketPassword())) {
            System.out.println("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Good passed");
            System.out.println("Market: " + marketName
                    + " Account: " + name
                    + " Get for " + name);

            return acc;
        } else {
            System.out.println("market account is not in cache, we check the dbb");
            ResultSet result = null;
            try {
                result = sqlStatement.executeQuery("SELECT * from client WHERE name='" + name + "'");
                if( !result.next() ){
                    throw new Rejected("no account with this name/password");
                }
                if ( passwordMarket.equalsIgnoreCase(result.getString("passwordMarket"))) {
                    // account exist, instantiate , put in cache
                    acc = new AccountClient(name, passwordMarket, this);
                    accountClient.put(name, acc);
                    result.close();
                    return acc;
                } else {
                    result.close();
                    throw new Rejected("no account with this name/password");
                }

            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }
        return acc;
    }

    @Override
    public synchronized AccountClientInter getAccount(String name) throws RemoteException, Rejected {
        AccountClientInter acc = (AccountClientInter) accountClient.get(name);
        if (acc != null) {
            System.out.println("Market: " + marketName
                    + " Account: " + name
                    + " Get for " + name);

            return acc;
        } else {
            System.out.println("market account is not in cache, we check the dbb");
            ResultSet result = null;
            try {
                result = sqlStatement.executeQuery("SELECT * from client WHERE name='" + name + "'");
                if (result.next()) {
                    // account exist, instantiate , put in cache
                    acc = new AccountClient(name, this);
                    accountClient.put(name, acc);
                    result.close();
                    return acc;
                } else {
                    result.close();
                    throw new Rejected("no account with the name " + name);
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }
        return acc;
    }

    @Override
    public synchronized boolean deleteAccount(AccountClientInter acc) throws RemoteException {
        boolean test = false;
        if (acc != null) {
            ResultSet result = null;
            try {
                sqlStatement.executeUpdate("DELETE FROM client WHERE name='" + acc.getClientName() + "'");
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }
        if ((acc != null) && (accountClient.contains(acc))) {
            java.util.Enumeration en = accountClient.keys();
            while (en.hasMoreElements()) {
                String name = (String) en.nextElement();
                AccountClient ai = (AccountClient) accountClient.get(name);
                AccountClient cmp = (AccountClient) ai;
                if (cmp.equals(acc)) {
                    accountClient.remove(name);
                    System.out.println("Market: " + marketName
                            + " Account for: " + name
                            + " is deleted");
                    test = true;
                }
            }
        }
        return test;
    }

    @Override
    public synchronized Vector getShowList() {
        Vector showList = new Vector();
        List listSell;
        // Add of all sell item and link between sell item and client
        ResultSet result1 = null;
        try {
            result1 = sqlStatementShowList.executeQuery("SELECT * FROM item");
            while (result1.next()) {
                String sellerName = result1.getString("sellerName");
                AccountClientInter acc = this.getAccount(sellerName);
                List sellList = acc.getSellList();
                System.out.println("Seller Name: " + result1.getString("sellerName"));
                System.out.println("Price : " + result1.getString("price"));
                System.out.println("SellList of the client size: " + sellList.size());
                System.out.println("Get the id of the item: " + result1.getInt("id"));
                boolean present = false;
                for (int i = 0; i < sellList.size(); i++) {
                    Item item = (Item) sellList.get(i);
                    System.out.println("number of time exploring the sellList: " + i);
                    System.out.println("Get the id of the item: " + result1.getInt("id"));
                    if (item.getId() == result1.getInt("id")) {
                        present = true;
                    }
                }
                if (!present) {
                    Item item = new Item(result1.getInt("id"), result1.getString("name"), result1.getInt("price"), result1.getInt("amount"), result1.getString("sellerName"), acc.getBankPassword(), acc);
                    sellList.add(item);
                    System.out.println("New item create and added to the list");
                }
            }
            result1.close();
        } catch (Rejected ex) {
            System.out.println(ex);
        } catch (SQLException ex) {
            System.out.println("erreur sql ds showList: ");
            ex.printStackTrace();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }

        Enumeration e = accountClient.elements();
        while (e.hasMoreElements()) {
            AccountClientInter acc = (AccountClientInter) e.nextElement();
            try {
                listSell = acc.getSellList();
                System.out.println("Refresh ask, size of the list : " + listSell.size());
                for (int i = 0; i < listSell.size(); i++) {
                    Vector row = new Vector();
                    row.add(0, acc);
                    row.add((Item) listSell.get(i));
                    showList.add(row);
                }
            } catch (RemoteException ex) {
                System.out.println("Error while getting sellList" + ex);
            }

        }
        return showList;
    }

    @Override
    public synchronized void changePrice(ItemInter item, AccountClientInter accOwner, int newPrice) {
        try {
            item.changePrice(accOwner, newPrice);
        } catch (RemoteException ex) {
            Logger.getLogger(Market.class.getName()).log(Level.SEVERE, null, ex);
        } catch (Rejected ex) {
            Logger.getLogger(Market.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    @Override
    public synchronized void buyItem(ItemInter item, AccountClientInter acc, String passBank) throws RemoteException, Rejected {
        item.buy(acc, passBank);
    }
}
